import axios from 'axios'
import { AxiosCancelError } from './AxiosCancelError'
import { setupInterceptor } from './AjaxInterceptors'

const instance = axios.create({ timeout: 30000, withCredentials: true })

const cancelReqMap = new Map()
const pendingReqMap = new Map()
const cacheReqPromiseMap = new Map()

instance.interceptors.request.use(
  function (config) {
    buildReqFlag(config)
    cancelReqAndRemoveCancelController(config)
    return config
  },
  function (error) {
    if (axios.isCancel(error)) {
      console.log('req捕获取消重复请求异常', error)
      return Promise.reject(
        new AxiosCancelError({ message: error.message, cause: error })
      )
    }
    return Promise.reject(error)
  }
)

instance.interceptors.response.use(
  function (response) {
    if (response.config) {
      removeCancelController(response.config)
    }
    return response
  },
  function (error) {
    if (error.response && error.response.config) {
      removeCancelController(error.response.config)
    }
    if (axios.isCancel(error)) {
      console.log('resp捕获取消重复请求异常', error)
      return Promise.reject(
        new AxiosCancelError({ message: error.message, cause: error })
      )
    }
    return Promise.reject(error)
  }
)

setupInterceptor(instance)

function buildReqFlag(config, autoSetToConfig = true) {
  const { method, url, params, data, reqFlag } = config
  if (reqFlag) return reqFlag

  let tmpFlag = `${method}:${url}`
  if (params) {
    tmpFlag += `:${JSON.stringify(params)}`
  }
  if (data && data instanceof Object) {
    tmpFlag += `:${JSON.stringify(data)}`
  }
  if (autoSetToConfig) {
    config.reqFlag = tmpFlag
  }
  console.log('tmpFlag', tmpFlag)
  return tmpFlag
}

function cancelReqAndRemoveCancelController(config) {
  const { cancelSame = false, reqFlag } = config
  if (cancelSame && reqFlag) {
    let abortController = removeCancelController(config)
    abortController?.abort(`取消请求[${reqFlag}]`)
    abortController = new AbortController()
    config.signal = abortController.signal
    cancelReqMap.set(reqFlag, abortController)
  }
}

function removeCancelController(config) {
  if (config) {
    const { reqFlag } = config
    if (reqFlag) {
      const abortController = cancelReqMap.get(reqFlag)
      if (abortController) {
        cancelReqMap.delete(reqFlag)
        return abortController
      }
    }
  }
  return undefined
}

function axiosReqMethodWrapper(config) {
  const { enableCache, cancelSame } = config
  const reqFlag = buildReqFlag(config)
  let responsePromise = cancelSame ? undefined : pendingReqMap.get(reqFlag)
  if (!responsePromise) {
    try {
      if (enableCache) {
        responsePromise = cacheReqPromiseMap.get(reqFlag)
      }
      if (!responsePromise) {
        responsePromise = instance(config).finally(() => {
          if (!cancelSame) {
            pendingReqMap.delete(reqFlag)
          }
        })
        if (!cancelSame) {
          pendingReqMap.set(reqFlag, responsePromise)
        }
        if (enableCache) {
          cacheReqPromiseMap.set(reqFlag, responsePromise)
        }
      } else {
        console.log(`${reqFlag} 请求已从从缓存中获取`)
      }
    } catch (e) {
      if (!cancelSame) {
        pendingReqMap.delete(reqFlag)
      }
      if (enableCache) {
        cacheReqPromiseMap.delete(reqFlag)
      }
      throw e
    }
  }
  return responsePromise
}

export function reqGet(url, config = {}) {
  return axiosReqMethodWrapper({ ...config, method: 'GET', url })
}

export function reqPost(url, config = {}) {
  return axiosReqMethodWrapper({ ...config, method: 'POST', url })
}

export function reqDel(url, config = {}) {
  return axiosReqMethodWrapper({ ...config, method: 'DELETE', url })
}

export const AjaxUtil = { reqGet, reqPost, reqDel }

export function setupAjax(app) {
  app.config.globalProperties.$ajax = { reqGet, reqPost, reqDel }
}

export default instance

export function extractFileNameFromAxiosResponse(response, defaultFileName) {
  const disposition = response.headers['content-disposition']
  console.log('disposition', disposition)
  if (disposition) {
    const pos = disposition.indexOf('=')
    if (pos >= 0) {
      return decodeURIComponent(disposition.substring(pos + 1))
    }
  }
  return defaultFileName
}
